package com.dev.op.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dev.op.VO.*;
import com.dev.op.config.CostumeProperties;
import com.dev.op.config.JudgeProperties;
import com.dev.op.entity.*;
import com.dev.op.enums.ResultCode;
import com.dev.op.enums.TestCaseResultCode;
import com.dev.op.exceptions.BizException;
import com.dev.op.mapper.SubmissionMapper;
import com.dev.op.service.*;


import com.dev.op.util.JudgeResultParser;
import com.dev.op.util.OutputComparator;
import com.dev.op.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author Administrator
* @description 针对表【submission】的数据库操作Service实现
* @createDate 2025-03-23 11:23:32
*/
@Service
public class SubmissionServiceImpl extends ServiceImpl<SubmissionMapper, Submission>
    implements SubmissionService {

    @Autowired
    private JudgeProperties judgeProperties;

    @Autowired
    OutputComparator outputComparator;

    @Autowired
    TestCaseService testCaseService;

    @Autowired
    JudgeService judgeService;

    @Autowired
    JudgeResultParser judgeResultParser;

    @Autowired
    ProblemService problemService;

    @Autowired
    SubmissionMapper submissionMapper;

    @Autowired
    RedisService redisService;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    CostumeProperties costumeProperties;
    /**
     * 构造JudgeRequest并保存Submission
     * @param submissionVO
     * @return
     * @throws Exception
     */
    @Override
    public Submission addSubmission(SubmissionVO submissionVO) throws Exception {
        Submission submission = submissionVO.getSubmission();
        Problem problem = problemService.getById(Integer.parseInt(submission.getProblemId()));
        //获取所有testCase
        List<TestCase> testCaseList = testCaseService.getTestCaseListByProblemId(problem.getProblemId());
        if( testCaseList==null || testCaseList.isEmpty()) {
            throw new BizException(ResultCode.TESTCASE_MISSING);
        }
        String code = submission.getCode();
        String language = submission.getLanguage();
        //改进
        String timeLimit = problem.getTimeLimit() != null? problem.getTimeLimit():judgeProperties.getSetting().getDefaultTimeLimit();
        String memLimit = problem.getMemLimit() != null? problem.getMemLimit():judgeProperties.getSetting().getDefaultMemLimit();
        List<TestCaseVO> testCases = new ArrayList<>();
        for(TestCase testCase: testCaseList){
            TestCaseVO testCaseVO = new TestCaseVO();
            testCaseVO.setInputData(testCase.getInputData());
            testCaseVO.setOutputData(testCase.getOutputData());
            testCases.add(testCaseVO);
        }
        //System.out.println("debug: 发送judge请求");
        JudgeRequest judgeRequest = new JudgeRequest(code,language,timeLimit,memLimit,testCases,submissionVO.isRunBatch());
        JudgeResultVO resultVO = judgeService.judge(judgeRequest);
        //System.out.println(resultVO);
        //根据约定，判题核心如果遇到第一个错误答案就会停止，所以从最后一个testcase: keyTestCase开始遍历
        //{status='ACCEPTED', time='0.04', mem='0', output='3', input='1 2', expected='3', error='null'}
        int len = resultVO.getResults().size();
        boolean accepted = true;
        double time = 0.0,mem = 0.0;
        String inputWrongAnswer = "";
        String expected = "";
        String output = "";
        String error = "";
        String status = "";
        int correctCount = 0;
        for (int i = 0; i <len ; i++) {
            JudgeTestCaseVO judgeTestCaseVO = resultVO.getResults().get(i);
            //全accepted才行
            if(!judgeTestCaseVO.getStatus().equals(TestCaseResultCode.ACCEPTED.flag())){
                accepted = false;
                inputWrongAnswer = judgeTestCaseVO.getInput();
                expected = judgeTestCaseVO.getExpected();
                output = judgeTestCaseVO.getOutput();
                error = judgeTestCaseVO.getError();
                status = judgeTestCaseVO.getStatus();
                break;
            }
            //计算使用时间
            correctCount++;
            time += Double.parseDouble(judgeTestCaseVO.getTime());
            mem += Double.parseDouble(judgeTestCaseVO.getMem());
        }
        //submission.setSubmissionId(UUID.randomUUID().toString());
        if(accepted){
            time /= (double)len;
            mem /= (double)len;
            //System.out.println("TIME:"+time);
            submission.setTimeUsed(String.valueOf(time));
            submission.setMemoryUsed(String.valueOf(mem));
            submission.setStatus(TestCaseResultCode.ACCEPTED.flag());
            submission.setPassRate("100%");
        }
        else{
            submission.setInputWrongAnswer(inputWrongAnswer);
            submission.setExpected(expected);
            submission.setStdout(output);
            submission.setError(error);
            submission.setStatus(status);
            submission.setPassRate( String.valueOf(correctCount/len) + "%" );
        }
        submission.setSubmitDate(new Date());
        submission.setProblemTitle(problem.getProblemTitle());
        //保存至redis
        redisService.saveSubmissionResult(submission,Long.parseLong(costumeProperties.getRedis().getSubmissionExpireTime()));
        //保存至数据库
        if(!submissionVO.isSampleTest()) {
            this.saveOrUpdate(submission);
        }
        return submission;
    }

    @Override
    public List<Submission> runSampleTestCases(Submission submission) throws Exception {
        Problem problem = problemService.getById(Integer.parseInt(submission.getProblemId()));
        //运行所有的testcase
        List<TestCase> testCaseList = testCaseService.getSampleTestCaseListByProblemId(problem.getProblemId());
        if( testCaseList == null || testCaseList.isEmpty()) {
            throw new BizException(ResultCode.TESTCASE_MISSING);
        }
        String code = submission.getCode();
        String language = submission.getLanguage();
        String timeLimit = problem.getTimeLimit() != null? problem.getTimeLimit():judgeProperties.getSetting().getDefaultTimeLimit();
        String memLimit = problem.getMemLimit() != null? problem.getMemLimit():judgeProperties.getSetting().getDefaultMemLimit();
        List<TestCaseVO> testCases = new ArrayList<>();
        //封装进 testcasevo
        for(TestCase testCase: testCaseList){
            TestCaseVO testCaseVO = new TestCaseVO();
            testCaseVO.setInputData(testCase.getInputData());
            testCaseVO.setOutputData(testCase.getOutputData());
            testCases.add(testCaseVO);
        }
        JudgeRequest judgeRequest = new JudgeRequest(code,language,timeLimit,memLimit,testCases,false);
        JudgeResultVO resultVO = judgeService.judge(judgeRequest);
        List<Submission> submissions = new ArrayList<>();
        //System.out.println("sample的大小"+resultVO.getResults().size());
        for (JudgeTestCaseVO judgeTestCaseVO: resultVO.getResults()) {
            Submission tmp = new Submission();
            //不通过的话
            if(!judgeTestCaseVO.getStatus().equals(TestCaseResultCode.ACCEPTED.flag())){
                tmp.setExpected(judgeTestCaseVO.getExpected());
                tmp.setStdout(judgeTestCaseVO.getOutput());
                tmp.setError(judgeTestCaseVO.getError());
                tmp.setStatus(judgeTestCaseVO.getStatus());
                tmp.setInputWrongAnswer(judgeTestCaseVO.getInput());
            }
            else{
                tmp.setStatus(judgeTestCaseVO.getStatus());
                tmp.setStdout(judgeTestCaseVO.getExpected());
                tmp.setExpected(judgeTestCaseVO.getExpected());
                tmp.setInputWrongAnswer(judgeTestCaseVO.getInput());
            }
            submissions.add(tmp);
        }
        return submissions;
    }

    @Override
    public Page<Submission> getSubmissionsByUserIdAndProblemId(int userId, String problemId, int page, int size) {
        Page<Submission> submissionPage = new Page<>(page, size);
        // 执行分页查询，返回分页结果
        return submissionMapper.selectPage(submissionPage,
               new LambdaQueryWrapper<Submission>().eq(Submission::getSubmitterUserId,userId)
                       .eq(Submission::getProblemId, problemId));
    }

    @Override
    public Page<Submission> getSubmissionByUserId(int userId, int page, int size) {
        Page<Submission> submissionPage = new Page<>(page, size);
        // 执行分页查询，返回分页结果
        return submissionMapper.selectPage(submissionPage,
                new LambdaQueryWrapper<Submission>().eq(Submission::getSubmitterUserId,userId));
    }

    @Override
    public Page<Submission> getSubmissionByProblemId(int problemId, int page, int size) {
        Page<Submission> submissionPage = new Page<>(page, size);
        // 执行分页查询，返回分页结果
        return submissionMapper.selectPage(submissionPage,
                new LambdaQueryWrapper<Submission>().eq(Submission::getProblemId, problemId));
    }


    @Override
    public void saveTask(SubmissionVO submissionVO) throws Exception {
        redisUtil.pushTask(submissionVO);
    }

    @Override
    public Submission getById(String id) throws Exception {
        try {
            //往redis找
            Submission submission = redisService.getSubmission(id);
            if (submission != null) {
                return submission;
            }
            //从数据库找
            //调用父类方法
            submission = super.getById(id);
            redisService.saveSubmissionResult(submission, Long.parseLong(costumeProperties.getRedis().getSubmissionExpireTime()));
            return submission;
        }
        catch (Exception e) {
            return null;
        }
    }
    /**
     拆分任务逻辑（拆成小任务）
     */
    @Override
    public void splitTaskAndPushToRedis(SubmissionVO submissionVO) throws Exception {
        Submission submission = submissionVO.getSubmission();
        //可redis优化
        Problem problem  = problemService.getProblemById(Integer.parseInt(submission.getProblemId())).getData();
        //没找到问题
        if(problem == null){
            System.out.println("没找到问题");
            return;
        }
        List<TestCase> testCases = testCaseService.getTestCaseListByProblemId(Integer.parseInt(submissionVO.getSubmission().getProblemId()));
        System.out.println("获取测试用例："+testCases.size());
        for(int i=0;i<testCases.size();i++){
            TestCase testCase = testCases.get(i);
            SubTask subTask = new SubTask(submission.getSubmissionId(),i,submission.getCode(), testCase.getInputData(),
                    testCase.getOutputData(),submission.getLanguage(),problem.getTimeLimit(),problem.getMemLimit());
            //System.out.println("子任务"+ i +"进队");
            //System.out.println(subTask);
            //进队
            //子任务结构
            redisUtil.pushSubTask(subTask);
        }
        // 填入元数据
        TaskVO taskVO = new TaskVO(
                submission.getSubmissionId(),
                null,
                testCases.size(),
                String.valueOf(submission.getSubmitterUserId()),
                submission.getCode(),
                String.valueOf(problem.getProblemId()),
                problem.getProblemTitle(),
                submission.getLanguage(),
                new Date()
        );
        redisUtil.pushSubmissionMetaData(taskVO,600);
    }
}




